home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / demos / GL / newton / draw.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  29KB  |  1,311 lines

  1. /*
  2.  * Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*
  18.  * model/room drawing stuff
  19.  * Yossi Friedman, July 1988
  20.  */
  21.  
  22. #include <stdio.h>
  23. #include <gl.h>
  24. #include <math.h>
  25.  
  26. #include "config.h"
  27. #include "newton.h"
  28.  
  29. /*
  30.  * constants
  31.  */
  32. #define SURF_TOL    (1. + 2. * (TOLERANCE - 1.))
  33. #define SHADOW_TOL    (1. + 1. * (TOLERANCE - 1.))
  34. #define DIST        (5. * HEIGHT)
  35.  
  36. /* RADIUS is the radius of the bounding circle of the room */
  37. #define RADIUS    (HEIGHT * (M_SQRT2 + 0.50))
  38.  
  39. #define GREY    18            /* wall color for bermuda mode */
  40.  
  41. static unsigned short halftone[] = {    /* shadow blending pattern */
  42.     0x5555, 0xaaaa, 0x5555, 0xaaaa,
  43.     0x5555, 0xaaaa, 0x5555, 0xaaaa,
  44.     0x5555, 0xaaaa, 0x5555, 0xaaaa,
  45.     0x5555, 0xaaaa, 0x5555, 0xaaaa
  46. };
  47. #define HALFTONE 1
  48.  
  49.  
  50.  
  51.  
  52. /*
  53.  * state variables
  54.  */
  55. static int new_M;            /* was M changed since last frame? */
  56. static int lighting;            /* is the lighting model truned on? */
  57.  
  58.  
  59.  
  60.  
  61. /*
  62.  * lighting model descriptors
  63.  */
  64. static float wall_material[MAX_LIGHTING_SIZE] = { WALL_MATERIAL };
  65. static int wall_material_size = WALL_MATERIAL_SIZE;
  66.  
  67. #define WALL_MATERIAL_INDEX    (MODEL_MATERIAL_INDEX + 1)
  68.  
  69. static float model_lmodel[MAX_LIGHTING_SIZE] = { MODEL_LMODEL };
  70. static int model_lmodel_size = MODEL_LMODEL_SIZE;
  71.  
  72. static float light[MAX_LIGHTING_SIZE] = { POSITION, LIGHT_VECTOR, 0., LMNULL };
  73. static int light_size = 6;
  74.  
  75.  
  76.  
  77. /*
  78.  * a vector pointing from the origin INTO the light source.  The _M
  79.  * contains the light vector in the MODELING (room) coordinate system, and
  80.  * the _V -- in the VIEWING coordinate system.  The idea is that the _V
  81.  * stays fixed.
  82.  */
  83. static float light_vec_V[3] = { LIGHT_VECTOR };
  84. static float light_vec_M[3] = { LIGHT_VECTOR };
  85.  
  86. void lighting_on();
  87. void lighting_off();
  88.  
  89. /*
  90.  * pinball mode variables, miscellaneaous variables
  91.  */
  92. static float red1 = RED1;
  93. static float red2 = RED2;
  94. static float green1 = GREEN1;
  95. static float green2 = GREEN2;
  96. static float blue1 = BLUE1;
  97. static float blue2 = BLUE2;
  98.  
  99. static float vel_factor = 0.;
  100.  
  101.  
  102. /*
  103.  * HEDGEHOG macro, for drawing normals (an essential debugging feature)
  104.  */
  105. #ifdef HEDGEHOG
  106. #   define draw_norm(v, norm)                        \
  107.         /* float v[3], norm[3] */                    \
  108.     do {                                \
  109.     float vert[3];                            \
  110.         if (mode == COLOR_MAP)                        \
  111.         color(BLUE);                        \
  112.     else                                \
  113.         RGBcolor(0, 0, 200);                    \
  114.     bgnline();                            \
  115.     v3f(v);                                \
  116.     vert[0] = v[X] + 10.0*norm[X];                    \
  117.     vert[1] = v[Y] + 10.0*norm[Y];                    \
  118.     vert[2] = v[Z] + 10.0*norm[Z];                    \
  119.     v3f(vert);                            \
  120.         if (mode == COLOR_MAP)                        \
  121.         color(YELLOW);                        \
  122.     else                                \
  123.         RGBcolor(200, 200, 0);                    \
  124.     vert[0] += 5.0*norm[X];                        \
  125.     vert[1] += 5.0*norm[Y];                        \
  126.     vert[2] += 5.0*norm[Z];                        \
  127.     v3f(vert);                            \
  128.     endline();                            \
  129.     } while (0)
  130. #else /* HEDGEHOG*/
  131. #   define draw_norm(v, norm)            do /* nothing */; while (0)
  132. #endif /* HEDGEHOG */
  133.  
  134.  
  135.  
  136.  
  137. initialize_draw()
  138. {
  139.     int n, i, j;
  140.  
  141.     /* initialize the relevant parts of the wall array */
  142.  
  143. #   define wall_verts(WALL, x1,y1,z1,  x2,y2,z2,  x3,y3,z3,  x4,y4,z4)    \
  144.     wall[WALL].real_v[0][X] = 0. x1 HEIGHT;                \
  145.     wall[WALL].real_v[0][Y] = 0. y1 HEIGHT;                \
  146.     wall[WALL].real_v[0][Z] = 0. z1 HEIGHT;                \
  147.                                                                     \
  148.     wall[WALL].real_v[1][X] = 0. x2 HEIGHT;                \
  149.     wall[WALL].real_v[1][Y] = 0. y2 HEIGHT;                \
  150.     wall[WALL].real_v[1][Z] = 0. z2 HEIGHT;                \
  151.                                                                     \
  152.     wall[WALL].real_v[2][X] = 0. x3 HEIGHT;                \
  153.     wall[WALL].real_v[2][Y] = 0. y3 HEIGHT;                \
  154.     wall[WALL].real_v[2][Z] = 0. z3 HEIGHT;                \
  155.                                                                     \
  156.     wall[WALL].real_v[3][X] = 0. x4 HEIGHT;                \
  157.     wall[WALL].real_v[3][Y] = 0. y4 HEIGHT;                \
  158.     wall[WALL].real_v[3][Z] = 0. z4 HEIGHT;                \
  159.                                                                     \
  160.     wall[WALL].surf_v[0][X] = 0. x1 SURF_TOL * HEIGHT;            \
  161.     wall[WALL].surf_v[0][Y] = 0. y1 SURF_TOL * HEIGHT;            \
  162.     wall[WALL].surf_v[0][Z] = 0. z1 SURF_TOL * HEIGHT;            \
  163.                                                                     \
  164.     wall[WALL].surf_v[1][X] = 0. x2 SURF_TOL * HEIGHT;            \
  165.     wall[WALL].surf_v[1][Y] = 0. y2 SURF_TOL * HEIGHT;            \
  166.     wall[WALL].surf_v[1][Z] = 0. z2 SURF_TOL * HEIGHT;            \
  167.                                                                     \
  168.     wall[WALL].surf_v[2][X] = 0. x3 SURF_TOL * HEIGHT;            \
  169.     wall[WALL].surf_v[2][Y] = 0. y3 SURF_TOL * HEIGHT;            \
  170.     wall[WALL].surf_v[2][Z] = 0. z3 SURF_TOL * HEIGHT;            \
  171.                                                                     \
  172.     wall[WALL].surf_v[3][X] = 0. x4 SURF_TOL * HEIGHT;            \
  173.     wall[WALL].surf_v[3][Y] = 0. y4 SURF_TOL * HEIGHT;            \
  174.     wall[WALL].surf_v[3][Z] = 0. z4 SURF_TOL * HEIGHT;            \
  175.                                     \
  176.     vec_op(wall[WALL].surf_e[0],                    \
  177.            wall[WALL].surf_v[1], -, wall[WALL].surf_v[0]);        \
  178.                                            \
  179.     vec_op(wall[WALL].surf_e[1],                    \
  180.            wall[WALL].surf_v[2], -, wall[WALL].surf_v[1]);        \
  181.                                     \
  182.     vec_op(wall[WALL].surf_e[2],                    \
  183.            wall[WALL].surf_v[3], -, wall[WALL].surf_v[2]);        \
  184.                                     \
  185.     vec_op(wall[WALL].surf_e[3],                    \
  186.            wall[WALL].surf_v[0], -, wall[WALL].surf_v[3])
  187.  
  188.     wall_verts(WALL_TOP,    +,+,-, +,+,+, -,+,+, -,+,-);
  189.     wall_verts(WALL_BOTTOM, +,-,-, -,-,-, -,-,+, +,-,+);
  190.     wall_verts(WALL_RIGHT,  +,-,+, +,+,+, +,+,-, +,-,-);
  191.     wall_verts(WALL_LEFT,   -,-,+, -,-,-, -,+,-, -,+,+);
  192.     wall_verts(WALL_FRONT,  -,+,+, +,+,+, +,-,+, -,-,+);
  193.     wall_verts(WALL_BACK,   -,+,-, -,-,-, +,-,-, +,+,-);
  194. #undef wall_verts
  195.  
  196.     wall[WALL_TOP]   .axis = Y;
  197.     wall[WALL_TOP]   .sign = 1.;
  198.     wall[WALL_TOP]   .real_norm[X] =  0.;
  199.     wall[WALL_TOP]   .real_norm[Y] = -1.;
  200.     wall[WALL_TOP]   .real_norm[Z] =  0.;
  201.  
  202.     wall[WALL_BOTTOM].axis = Y;
  203.     wall[WALL_BOTTOM].sign = -1.;
  204.     wall[WALL_BOTTOM].real_norm[X] =  0.;
  205.     wall[WALL_BOTTOM].real_norm[Y] =  1.;
  206.     wall[WALL_BOTTOM].real_norm[Z] =  0.;
  207.  
  208.     wall[WALL_RIGHT] .axis = X;
  209.     wall[WALL_RIGHT] .sign = 1.;
  210.     wall[WALL_RIGHT] .real_norm[X] = -1.;
  211.     wall[WALL_RIGHT] .real_norm[Y] =  0.;
  212.     wall[WALL_RIGHT] .real_norm[Z] =  0.;
  213.  
  214.     wall[WALL_LEFT]  .axis = X;
  215.     wall[WALL_LEFT]  .sign = -1.;
  216.     wall[WALL_LEFT]  .real_norm[X] =  1.;
  217.     wall[WALL_LEFT]  .real_norm[Y] =  0.;
  218.     wall[WALL_LEFT]  .real_norm[Z] =  0.;
  219.  
  220.     wall[WALL_FRONT] .axis = Z;
  221.     wall[WALL_FRONT] .sign = 1.;
  222.     wall[WALL_FRONT] .real_norm[X] =  0.;
  223.     wall[WALL_FRONT] .real_norm[Y] =  0.;
  224.     wall[WALL_FRONT] .real_norm[Z] = -1.;
  225.  
  226.     wall[WALL_BACK]  .axis = Z;
  227.     wall[WALL_BACK]  .sign = -1.;
  228.     wall[WALL_BACK]  .real_norm[X] =  0.;
  229.     wall[WALL_BACK]  .real_norm[Y] =  0.;
  230.     wall[WALL_BACK]  .real_norm[Z] =  1.;
  231.  
  232.     for (n = 0; n < 6; n++)
  233.     for (i = 0; i < 4; i++)
  234.         for (j = 0; j < 4; j++)
  235.         wall[n].shadow[i][j] = ident_matrix[i][j];
  236.  
  237.     /* define the pattern used for shadows */
  238.     defpattern(HALFTONE, 16, halftone);
  239. }
  240.  
  241.  
  242. long
  243. open_model_window(char *title)
  244. {
  245.     long wid;
  246.  
  247.     keepaspect(5, 4);
  248.  
  249.     foreground();
  250.  
  251.     wid = winopen(title);
  252.      if (getgdesc(GD_BITS_NORM_SNG_RED) == 0)
  253.      {
  254.           system("inform 'Your system must support RGB mode to run newton'");
  255.             exit(1);
  256.     }
  257.      if (getgdesc(GD_BITS_NORM_ZBUFFER) == 0)
  258.      {
  259.          system("inform 'Your system must have a z-buffer to run newton'");
  260.           exit(1);
  261.     }
  262.  
  263.     keepaspect(5, 4);
  264.     winconstraints();
  265.     wintitle("Newton Model");
  266.     
  267.     doublebuffer();
  268.     if (mode == RGB)
  269.     RGBmode();
  270.     else
  271.     cmode();
  272.     gconfig();
  273.  
  274.     zbuffer(TRUE);
  275.  
  276. #ifdef HAS_CZCLEAR
  277.     zfunction(ZF_GEQUAL);
  278.     /* lsetdepth(0x7fffff, 0x2000); */
  279.      lsetdepth((getgdesc(GD_ZMAX)), 0x2000);
  280. #else /* HAS_CZCLEAR */
  281.     setdepth(0xc000, 0x3fff);
  282. #endif /* HAS_CZCLEAR */
  283.  
  284.     lmdef(DEFLMODEL, 1, model_lmodel_size, model_lmodel);
  285.     lmdef(DEFLIGHT, 1, light_size, light);
  286.     lmdef(DEFMATERIAL, WALL_MATERIAL_INDEX, wall_material_size, wall_material);
  287.  
  288.     /* set the light vector */
  289.     normalize(light_vec_V);
  290.     apply(light_vec_M, light_vec_V, M_inv);
  291.  
  292.     lighting_off();
  293.     lighting_on();
  294.     return(wid);
  295. }
  296.  
  297.  
  298. void
  299. close_model_window(long wid)
  300. {
  301.     lighting_off();
  302.     winclose(wid);
  303. }
  304.  
  305.  
  306. #ifdef CONFIG_FILE
  307.  
  308. initialize_config()
  309. {
  310.     FILE *fp;
  311.     char line[200], *p;
  312.     int n, q;
  313.     float f;
  314.     
  315.     fp = fopen(model_config, "r");
  316.     if (fp == NULL) {
  317.     fprintf(stderr, "newton: Could not open ");
  318.     if (model_config[0] == '/')
  319.         fprintf(stderr, "%s\n", model_config);
  320.     else
  321.         fprintf(stderr, "%s/%s\n", cwd(), model_config);
  322.     my_exit(1);
  323.     }
  324.     while (fgets(line, 200, fp) != NULL)
  325.     switch (line[0]) {
  326.       case '\n':
  327.       case '#':
  328.         continue;
  329.  
  330.       case 'v':
  331.         sscanf(line + 1, "%f", &vel_factor);
  332.         break;
  333.  
  334.       case 'r':
  335.         sscanf(line + 1, "%f %f", &red1, &red2);
  336.         break;
  337.  
  338.       case 'g':
  339.         sscanf(line + 1, "%f %f", &green1, &green2);
  340.         break;
  341.  
  342.       case 'b':
  343.         sscanf(line + 1, "%f %f", &blue1, &blue2);
  344.         break;
  345.  
  346.       case 'l':
  347.         p = line + 1;
  348.         for (n = 0; sscanf(p, "%f%n", &f, &q) == 1; p += q) {
  349.         if (n == MAX_LIGHTING_SIZE) {
  350.             fprintf(stderr, "newton: Light too big\n");
  351.             my_exit(1);
  352.         }
  353.         light[n++] = f;
  354.         }
  355.         if (light[0] == POSITION) {
  356.         light_vec_V[X] = light[1];
  357.         light_vec_V[Y] = light[2];
  358.         light_vec_V[Z] = light[3];
  359.         }
  360.         light_size = n;
  361.         break;
  362.  
  363.       case 'L':
  364.         p = line + 1;
  365.         for (n = 0; sscanf(p, "%f%n", &f, &q) == 1; p += q) {
  366.         if (n == MAX_LIGHTING_SIZE) {
  367.             fprintf(stderr, "newton: Lighting model too big\n");
  368.             my_exit(1);
  369.         }
  370.         model_lmodel[n++] = f;
  371.         }
  372.         model_lmodel_size = n;
  373.         break;
  374.  
  375.       case 'J':
  376.         p = line + 1;
  377.         for (n = 0; sscanf(p, "%f%n", &f, &q) == 1; p += q) {
  378.         if (n == MAX_LIGHTING_SIZE) {
  379.             fprintf(stderr, "newton: Default model material too big\n");
  380.             my_exit(1);
  381.         }
  382.         default_model_material[n++] = f;
  383.         }
  384.         default_model_material_size = n;
  385.         break;
  386.  
  387.       case 'W':
  388.         p = line + 1;
  389.         for (n = 0; sscanf(p, "%f%n", &f, &q) == 1; p += q) {
  390.         if (n == MAX_LIGHTING_SIZE) {
  391.             fprintf(stderr, "newton: Wall material too big\n");
  392.             my_exit(1);
  393.         }
  394.         wall_material[n++] = f;
  395.         }
  396.         wall_material_size = n;
  397.         break;
  398.  
  399.       default:
  400.         fprintf(stderr, "newton: Syntax error in config file: \"%s\"\n", line);
  401.         my_exit(1);
  402.     }
  403. }
  404.  
  405. #endif /* CONFIG_FILE */
  406.  
  407.  
  408.  
  409. rotate_graphics(Angle alpha,char axis)
  410. {
  411.     /* adjust M */
  412.     pushmatrix();
  413.       loadmatrix(ident_matrix);
  414.       rotate(alpha, axis);
  415.       multmatrix(M);
  416.       getmatrix(M);
  417.     popmatrix();
  418.  
  419.     /* adjust M inverse */
  420.     pushmatrix();
  421.       loadmatrix(M_inv);
  422.       rotate(-alpha, axis);
  423.       getmatrix(M_inv);
  424.     popmatrix();
  425.  
  426.     new_M = 1;
  427.  
  428.     /* set the light vector */
  429.     apply(light_vec_M, light_vec_V, M_inv);
  430. }
  431.  
  432.  
  433. draw_everything()
  434. {
  435.     swapbuffers();
  436.  
  437. #ifdef HAS_CZCLEAR
  438.     czclear(0, 0);
  439. #else /* HAS_CZCLEAR */
  440.     if (mode == COLOR_MAP)
  441.     color(BLACK);
  442.     else
  443.     RGBcolor(0, 0, 0);
  444.     clear();
  445.     zclear();
  446. #endif /* HAS_CZCLEAR */
  447.     
  448.     if (new_M) {
  449.     loadmatrix(ident_matrix);
  450.     lookat(0.,0.,DIST,  0.,0.,0.,  0);
  451.     multmatrix(M);
  452.  
  453.     new_M = 0;
  454.     }
  455.  
  456.     draw_room();
  457.     (*draw_model)();
  458.     if (springs_too)
  459.     draw_springs();
  460. }
  461.  
  462.  
  463. draw_room()
  464. {
  465.     void  (*actual_draw_wall)(int);
  466.     
  467.     if (mode == RGB)
  468.     actual_draw_wall = draw_wall;
  469.     else
  470.     actual_draw_wall = draw_plain_wall;
  471.  
  472.     /* draw the wall surfaces */
  473.     if (M[Y][Z] < HEIGHT/DIST)
  474.     (*actual_draw_wall)(WALL_TOP);
  475.  
  476.     if (M[Y][Z] > -HEIGHT/DIST)
  477.     (*actual_draw_wall)(WALL_BOTTOM);
  478.  
  479.     if (M[X][Z] < HEIGHT/DIST)
  480.     (*actual_draw_wall)(WALL_RIGHT);
  481.  
  482.     if (M[X][Z] > -HEIGHT/DIST)
  483.     (*actual_draw_wall)(WALL_LEFT);
  484.  
  485.     if (M[Z][Z] < HEIGHT/DIST)
  486.     (*actual_draw_wall)(WALL_FRONT);
  487.  
  488.     if (M[Z][Z] > -HEIGHT/DIST)
  489.     (*actual_draw_wall)(WALL_BACK);
  490.  
  491.     /* draw the frame itself */
  492.     if (mode == COLOR_MAP)
  493.     color(BLUE);
  494.     else
  495.     RGBcolor(50, 100, 255);
  496.     
  497. #ifdef HAS_CZCLEAR
  498.     zfunction(ZF_ALWAYS);
  499. #endif /* HAS_CZCLEAR */
  500.  
  501.     bgnline();
  502.       v3f(wall[WALL_BOTTOM].surf_v[0]);
  503.       v3f(wall[WALL_BOTTOM].surf_v[1]);
  504.       v3f(wall[WALL_BOTTOM].surf_v[2]);
  505.       v3f(wall[WALL_BOTTOM].surf_v[3]);
  506.       v3f(wall[WALL_BOTTOM].surf_v[0]);
  507.  
  508.       v3f(wall[WALL_TOP].surf_v[0]);
  509.       v3f(wall[WALL_TOP].surf_v[3]);
  510.       v3f(wall[WALL_TOP].surf_v[2]);
  511.       v3f(wall[WALL_TOP].surf_v[1]);
  512.       v3f(wall[WALL_TOP].surf_v[0]);
  513.     endline();
  514.     bgnline();
  515.       v3f(wall[WALL_BOTTOM].surf_v[1]);
  516.       v3f(wall[WALL_TOP].surf_v[3]);
  517.     endline();
  518.     bgnline();
  519.       v3f(wall[WALL_BOTTOM].surf_v[2]);
  520.       v3f(wall[WALL_TOP].surf_v[2]);
  521.     endline();
  522.     bgnline();
  523.       v3f(wall[WALL_BOTTOM].surf_v[3]);
  524.       v3f(wall[WALL_TOP].surf_v[1]);
  525.     endline();
  526.  
  527. #ifdef HAS_CZCLEAR
  528.     zfunction(ZF_GEQUAL);
  529. #endif /* HAS_CZCLEAR */
  530.  
  531. }
  532.  
  533.  
  534. void
  535. draw_lighted_wall(int n)
  536. {
  537.     struct wall *w = &wall[n];
  538.     float e[3], pos[3], f_norm[4][3], vel_correction;
  539.     float rotm[4][4], rotm_inv[4][4], cos_beta, sin_beta;
  540.     int axis1, axis2, axis3;
  541.     int t;
  542.  
  543.     lighting_on();
  544.     lmbind(MATERIAL, WALL_MATERIAL_INDEX);
  545.  
  546.     axis1 = w->axis;
  547.  
  548.     if (w->penetrated) {
  549.  
  550.         /*
  551.          *  move pos slightly outward, to prevent annoying artifacts
  552.          */
  553.         pos[X] = w->atom->pos[X];
  554.         pos[Y] = w->atom->pos[Y];
  555.         pos[Z] = w->atom->pos[Z];
  556.     pos[axis1] *= SURF_TOL;
  557.     
  558.     vel_correction = vel_factor * w->atom->vel[w->axis];
  559.     if (vel_correction < 0)
  560.         vel_correction = -vel_correction;
  561.     pos[w->axis] += w->sign * vel_correction;
  562.  
  563.     /*
  564.      * calculate the normals to each triangular face
  565.      */
  566.         vec_op(e, w->surf_v[0], -, pos);
  567.         cross(f_norm[0], e, w->surf_e[0]);
  568.         normalize(f_norm[0]);
  569.  
  570.         vec_op(e, w->surf_v[1], -, pos);
  571.         cross(f_norm[1], e, w->surf_e[1]);
  572.         normalize(f_norm[1]);
  573.  
  574.         vec_op(e, w->surf_v[2], -, pos);
  575.         cross(f_norm[2], e, w->surf_e[2]);
  576.         normalize(f_norm[2]);
  577.  
  578.         vec_op(e, w->surf_v[3], -, pos);
  579.         cross(f_norm[3], e, w->surf_e[3]);
  580.         normalize(f_norm[3]);
  581.  
  582.         /*
  583.          * calculate the normals at the vertices
  584.      */
  585.         vec_op(w->surf_norm[0], f_norm[3], +, f_norm[0]);
  586.         normalize(w->surf_norm[0]);
  587.  
  588.         vec_op(w->surf_norm[1], f_norm[0], +, f_norm[1]);
  589.         normalize(w->surf_norm[1]);
  590.  
  591.         vec_op(w->surf_norm[2], f_norm[1], +, f_norm[2]);
  592.         normalize(w->surf_norm[2]);
  593.  
  594.         vec_op(w->surf_norm[3], f_norm[2], +, f_norm[3]);
  595.         normalize(w->surf_norm[3]);
  596.  
  597.         vec_op(w->surf_norm[4], f_norm[0], +, f_norm[1]);
  598.         vec_op(w->surf_norm[4], w->surf_norm[4], +, f_norm[2]);
  599.         vec_op(w->surf_norm[4], w->surf_norm[4], +, f_norm[3]);
  600.         normalize(w->surf_norm[4]);
  601.  
  602.     /*
  603.      * draw the triangles
  604.      */
  605.     bgnpolygon();
  606.       n3f(w->surf_norm[0]); v3f(w->surf_v[0]);
  607.       n3f(w->surf_norm[1]); v3f(w->surf_v[1]);
  608.       n3f(w->surf_norm[4]); v3f(pos);
  609.     endpolygon();
  610.     bgnpolygon();    
  611.       n3f(w->surf_norm[1]); v3f(w->surf_v[1]);
  612.       n3f(w->surf_norm[2]); v3f(w->surf_v[2]);
  613.       n3f(w->surf_norm[4]); v3f(pos);
  614.     endpolygon();
  615.     bgnpolygon();
  616.       n3f(w->surf_norm[2]); v3f(w->surf_v[2]);
  617.       n3f(w->surf_norm[3]); v3f(w->surf_v[3]);
  618.       n3f(w->surf_norm[4]); v3f(pos);
  619.     endpolygon();
  620.     bgnpolygon();    
  621.       n3f(w->surf_norm[3]); v3f(w->surf_v[3]);
  622.       n3f(w->surf_norm[0]); v3f(w->surf_v[0]);
  623.       n3f(w->surf_norm[4]); v3f(pos);
  624.     endpolygon();
  625.  
  626.  
  627.         draw_norm(w->surf_v[0], w->surf_norm[0]);
  628.     draw_norm(w->surf_v[1], w->surf_norm[1]);
  629.     draw_norm(w->surf_v[2], w->surf_norm[2]);
  630.     draw_norm(w->surf_v[3], w->surf_norm[3]);
  631.     draw_norm(pos, w->surf_norm[4]);
  632.  
  633.     if (shadows_too == 0)
  634.         goto finale;
  635.  
  636.     /*
  637.      * check if a shadow is cast on the triangles.  The condition is that
  638.      * the normal to the triangle has a positive component in the direction
  639.      * of the light.
  640.      */
  641.     for (t = 0; t < 4; t++ )
  642.         if (dot(light_vec_M, f_norm[t]) > 0.) {
  643.         
  644.         lighting_off();
  645.         
  646.         axis2 = (axis1 + 1) % 3;
  647.         if (w->surf_v[t][axis2] != w->surf_v[(t+1)%4][axis2])
  648.             axis2 = (axis1 + 2) % 3;
  649.         
  650.         axis3 = (X + Y + Z) - (axis1 + axis2);
  651.         
  652.         /*
  653.          * the following code generates a rotation matrix
  654.          * of beta degrees around axis3
  655.          */
  656.         cos_beta = dot(f_norm[t], w->real_norm);
  657.         sin_beta = sqrt(1. - cos_beta * cos_beta);
  658.         cross(e, f_norm[t], w->real_norm);
  659.         if (e[axis3] < 0.)
  660.             sin_beta = -sin_beta;
  661.  
  662.         memcpy(rotm, ident_matrix, 4 * 4 *sizeof(float));
  663.         memcpy(rotm_inv, ident_matrix, 4 * 4 *sizeof(float));
  664.             rotm[axis1][axis1] =
  665.             rotm[axis2][axis2] =
  666.             rotm_inv[axis1][axis1] =
  667.             rotm_inv[axis2][axis2] = cos_beta;
  668.         if (axis3 != Y)
  669.             if (axis1 < axis2) {
  670.             rotm[axis1][axis2] = sin_beta;
  671.             rotm[axis2][axis1] = -sin_beta;
  672.             rotm_inv[axis1][axis2] = -sin_beta;
  673.             rotm_inv[axis2][axis1] = sin_beta;
  674.             }
  675.             else {
  676.             rotm[axis2][axis1] = sin_beta;
  677.             rotm[axis1][axis2] = -sin_beta;
  678.             rotm_inv[axis2][axis1] = -sin_beta;
  679.             rotm_inv[axis1][axis2] = sin_beta;
  680.             }
  681.         else /* axis3 is Y */
  682.             if (axis1 < axis2) {
  683.             rotm[axis1][axis2] = -sin_beta;
  684.             rotm[axis2][axis1] = sin_beta;
  685.             rotm_inv[axis1][axis2] = sin_beta;
  686.             rotm_inv[axis2][axis1] = -sin_beta;
  687.             }
  688.             else {
  689.             rotm[axis2][axis1] = -sin_beta;
  690.             rotm[axis1][axis2] = sin_beta;
  691.             rotm_inv[axis2][axis1] = sin_beta;
  692.             rotm_inv[axis1][axis2] = -sin_beta;
  693.             }
  694.  
  695.         /* need to rotate the light vector as well */
  696.         apply(e, light_vec_M, rotm);
  697.  
  698.         w->shadow[axis1][axis1] = 0.;
  699.         w->shadow[axis1][axis2] = - e[axis2] /
  700.                                     e[axis1];
  701.         w->shadow[axis1][axis3] = - e[axis3] /
  702.                                             e[axis1];
  703.         e[axis1] = w->atom->pos[axis1] * SHADOW_TOL;
  704.         e[axis2] = w->atom->pos[axis2];
  705.         e[axis3] = w->atom->pos[axis3];
  706.         translate(
  707.             e[X],
  708.             e[Y],
  709.             e[Z]
  710.                 );
  711.         multmatrix(rotm_inv);
  712.         multmatrix(w->shadow);
  713.         multmatrix(rotm);
  714.         translate(
  715.                     - w->atom->pos[X],
  716.                     - w->atom->pos[Y],
  717.                     - w->atom->pos[Z]
  718.                 );
  719.  
  720.         draw_shadows();
  721.         }
  722.  
  723.     lighting_on();
  724.     }
  725.     else {
  726.     bgnpolygon();
  727.       n3f(w->real_norm);
  728.       v3f(w->surf_v[0]);
  729.       v3f(w->surf_v[1]);
  730.       v3f(w->surf_v[2]);
  731.       v3f(w->surf_v[3]);
  732.     endpolygon();
  733.  
  734.  
  735. #ifdef HEDGEHOG
  736.  
  737.     axis2 = (axis1 + 1) % 3;
  738.     axis3 = (axis1 + 2) % 3;
  739.     e[axis1] = w->sign * HEIGHT;
  740.     e[axis2] = e[axis3] = 0.;
  741.     draw_norm(e, w->real_norm);
  742.  
  743. #endif /* HEDGEHOG */
  744.  
  745.     if (shadows_too == 0)
  746.         goto finale;
  747.  
  748.     /*
  749.      * check if a shadow is cast on the wall.  The condition is that
  750.      * the normal to the wall has a positive component in the direction
  751.      * of the light.
  752.      */
  753.     if (dot(light_vec_M, w->real_norm) > 0.) {
  754.         
  755.         axis2 = (axis1 + 1) % 3;
  756.         axis3 = (axis1 + 2) % 3;
  757.         lighting_off();
  758.         
  759.         w->shadow[axis1][axis1] = 0.;
  760.         w->shadow[axis1][axis2] = - light_vec_M[axis2] /
  761.                                 light_vec_M[axis1];
  762.         w->shadow[axis1][axis3] = - light_vec_M[axis3] /
  763.                                         light_vec_M[axis1];
  764.  
  765.         e[axis1] = w->sign * HEIGHT * SHADOW_TOL;
  766.         e[axis2] = e[axis3] = 0.;
  767.  
  768.         translate(e[X], e[Y], e[Z]);
  769.         multmatrix(w->shadow);
  770.  
  771.         e[axis1] = - w->sign * HEIGHT;
  772.         translate(e[X], e[Y], e[Z]);
  773.  
  774.         draw_shadows();
  775.  
  776.         lighting_on();
  777.     }
  778.     }
  779.  
  780.  
  781. finale:
  782.  
  783.     hide_wall_exterior(n);
  784. }
  785.  
  786.  
  787. void
  788. draw_pinball_wall(int n)
  789. {
  790.     struct wall *w = &wall[n];
  791.     float pos[3];
  792.     float basic_color[3], color[3];
  793.  
  794.     basic_color[0] = red2;
  795.     basic_color[1] = green2;
  796.     basic_color[2] = blue2;
  797.  
  798.     if (w->penetrated) {
  799.     /*
  800.      * calculate the colors
  801.      */
  802.     color[0] =   red1 * w->depth + red2;
  803.     if (color[0] > 1.0)
  804.         color[0] = 1.0;
  805.     color[1] = green1 * w->depth + green2;
  806.     if (color[1] > 1.0)
  807.         color[1] = 1.0;
  808.     color[2] = blue1 * w->depth + blue2;
  809.     if (color[2] > 1.0)
  810.         color[2] = 1.0;
  811.  
  812.         /*
  813.          *  move pos slightly outward, to prevent annoying artifacts
  814.          */
  815.         pos[X] = w->atom->pos[X];
  816.         pos[Y] = w->atom->pos[Y];
  817.         pos[Z] = w->atom->pos[Z];
  818.     pos[w->axis] *= SURF_TOL;
  819.  
  820.     /*
  821.      * draw the triangles
  822.      */
  823.     bgnpolygon();
  824.       c3f(basic_color); v3f(w->surf_v[0]);
  825.       c3f(basic_color); v3f(w->surf_v[1]);
  826.       c3f(color); v3f(pos);
  827.     endpolygon();
  828.     bgnpolygon();
  829.       c3f(basic_color); v3f(w->surf_v[1]);
  830.       c3f(basic_color); v3f(w->surf_v[2]);
  831.       c3f(color); v3f(pos);
  832.     endpolygon();
  833.     bgnpolygon();
  834.       c3f(basic_color); v3f(w->surf_v[2]);
  835.       c3f(basic_color); v3f(w->surf_v[3]);
  836.       c3f(color); v3f(pos);
  837.     endpolygon();
  838.     bgnpolygon();
  839.       c3f(basic_color); v3f(w->surf_v[3]);
  840.       c3f(basic_color); v3f(w->surf_v[0]);
  841.       c3f(color); v3f(pos);
  842.     endpolygon();
  843.     }
  844.     else {
  845.     bgnpolygon();
  846.           c3f(basic_color);
  847.       v3f(w->surf_v[0]);
  848.       v3f(w->surf_v[1]);
  849.       v3f(w->surf_v[2]);
  850.       v3f(w->surf_v[3]);
  851.     endpolygon();
  852.     }
  853.  
  854.     hide_wall_exterior(n);
  855. }
  856.  
  857.  
  858. void
  859. draw_plain_wall(int n)
  860. {
  861.     struct wall *w = &wall[n];
  862.     float pos[3];
  863.  
  864.     if (w->penetrated) {
  865.         /*
  866.          *  move pos slightly outward, to prevent annoying artifacts
  867.          */
  868.         pos[X] = w->atom->pos[X] * SURF_TOL;
  869.         pos[Y] = w->atom->pos[Y] * SURF_TOL;
  870.         pos[Z] = w->atom->pos[Z] * SURF_TOL;
  871.  
  872.     /*
  873.      * draw the triangles
  874.      */
  875.     bgnpolygon();
  876.       color(GREY); v3f(w->surf_v[0]);
  877.       color(GREY); v3f(w->surf_v[1]);
  878.       color(GREY); v3f(pos);
  879.     endpolygon();
  880.     bgnpolygon();
  881.       color(GREY); v3f(w->surf_v[1]);
  882.       color(GREY); v3f(w->surf_v[2]);
  883.       color(GREY); v3f(pos);
  884.     endpolygon();
  885.     bgnpolygon();
  886.       color(GREY); v3f(w->surf_v[2]);
  887.       color(GREY); v3f(w->surf_v[3]);
  888.       color(GREY); v3f(pos);
  889.     endpolygon();
  890.     bgnpolygon();
  891.       color(GREY); v3f(w->surf_v[3]);
  892.       color(GREY); v3f(w->surf_v[0]);
  893.       color(GREY); v3f(pos);
  894.     endpolygon();
  895.     }
  896.     else {
  897.     bgnpolygon();
  898.           color(GREY);
  899.       v3f(w->surf_v[0]);
  900.       v3f(w->surf_v[1]);
  901.       v3f(w->surf_v[2]);
  902.       v3f(w->surf_v[3]);
  903.     endpolygon();
  904.     }
  905.  
  906.     hide_wall_exterior(n);
  907. }
  908.  
  909.  
  910. /*
  911.  * hide the back side of the wall, so that the body is not seen
  912.  * penetrating the wall
  913.  */
  914. hide_wall_exterior(int n)
  915. {
  916.     struct wall *w = &wall[n];
  917.     float corner[4][3];
  918.     int i, j;
  919.     
  920.     for (i = 0; i < 4; i++) {
  921.     for (j = X; j <= Z; j++)
  922.         corner[i][j] = w->surf_v[i][j];
  923.     corner[i][w->axis] += w->sign * HEIGHT;
  924.     }
  925.     
  926.     backbuffer(FALSE);
  927.     
  928.     bgnpolygon();
  929.       v3f(w->surf_v[0]);
  930.       v3f(corner[0]);
  931.       v3f(corner[1]);
  932.       v3f(w->surf_v[1]);
  933.     endpolygon();
  934.     
  935.     bgnpolygon();
  936.       v3f(w->surf_v[1]);
  937.       v3f(corner[1]);
  938.       v3f(corner[2]);
  939.       v3f(w->surf_v[2]);
  940.     endpolygon();
  941.     
  942.     bgnpolygon();
  943.       v3f(w->surf_v[2]);
  944.       v3f(corner[2]);
  945.       v3f(corner[3]);
  946.       v3f(w->surf_v[3]);
  947.     endpolygon();
  948.     
  949.     bgnpolygon();
  950.       v3f(w->surf_v[3]);
  951.       v3f(corner[3]);
  952.       v3f(corner[0]);
  953.       v3f(w->surf_v[0]);
  954.     endpolygon();
  955.     
  956.     backbuffer(TRUE);
  957. }
  958.  
  959.  
  960.  
  961. void
  962. lighting_off()
  963. {
  964.     if (lighting == 0)
  965.     return;
  966.  
  967.     lmbind(MATERIAL, 0);
  968.     lmbind(LMODEL, 0);
  969.     lmbind(LIGHT0, 0);
  970.  
  971.     mmode(MSINGLE);
  972.     loadmatrix(ident_matrix);
  973.     perspective(400, 5./4., DIST - RADIUS, DIST + RADIUS);
  974.     lookat(0.,0.,DIST,  0.,0.,0.,  0);
  975.  
  976.     multmatrix(M);
  977.  
  978.     lighting = 0;
  979. }
  980.  
  981. void
  982. lighting_on()
  983. {
  984.     if (lighting == 1)
  985.     return;
  986.  
  987.  
  988. #ifdef CLOVER1            /* 4D gl bug */
  989.     loadmatrix(ident_matrix);
  990. #endif /* CLOVER1 */
  991.  
  992.     mmode(MVIEWING);
  993.     loadmatrix(ident_matrix);
  994.     perspective(400, 5./4., DIST - RADIUS, DIST + RADIUS);
  995.     lookat(0.,0.,DIST,  0.,0.,0.,  0);
  996.  
  997.     lmbind(LIGHT0, 1);
  998.     lmbind(LMODEL, 1);
  999.  
  1000.     multmatrix(M);
  1001.  
  1002.     lighting = 1;
  1003. }
  1004.  
  1005.  
  1006. draw_shadows()
  1007. {
  1008.     Surf *sp;
  1009.     int i;
  1010.  
  1011.     zwritemask(0);
  1012.  
  1013.     setpattern(HALFTONE);
  1014.  
  1015.     if (mode == COLOR_MAP)
  1016.     color(BLACK);
  1017.     else
  1018.     RGBcolor(0, 0, 0);
  1019.     
  1020.     for (sp = model_surfs; sp < end_model_surfs TOTAL; sp++) {
  1021.  
  1022.     bgnpolygon();
  1023.  
  1024.     for (i = 0; i < sp->n; i++)
  1025.         v3f((sp->vert[i])->pos);
  1026.  
  1027.     endpolygon();
  1028.     }
  1029.  
  1030.     setpattern(0);
  1031.  
  1032.     zwritemask(0xffffff);
  1033. }
  1034.  
  1035.  
  1036. void
  1037. draw_flat_surfs()
  1038. {
  1039.     float *v, *norm;
  1040.     Surf *sp;
  1041.     int i, n;
  1042.     
  1043.     /*
  1044.      * PHASE I: compute the normals
  1045.      */
  1046.     SLAVE_FUNC(DRAW_FLAT_SURFS_1);
  1047.     draw_flat_surfs_1(model_surfs, end_model_surfs MASTER);
  1048.     WAIT_FOR_SLAVE();
  1049.  
  1050.     /*
  1051.      * PHASE II: draw surfaces
  1052.      */
  1053.  
  1054. #ifdef HAS_BLENDING
  1055.     if (alpha_blended) {
  1056.     blendfunction(BF_SA, BF_MSA);
  1057.     zwritemask(0);
  1058.     }
  1059. #endif /* HAS_BLENDING */
  1060.  
  1061.     lmbind(MATERIAL, MODEL_MATERIAL_INDEX);
  1062.  
  1063.     for (sp = model_surfs; sp < end_model_surfs TOTAL; sp++) {
  1064.  
  1065.     n = sp->n;
  1066.  
  1067.     bgnpolygon();
  1068.  
  1069.     for (i = 0; i < n; i++) {
  1070.         v = (sp->vert[i])->pos;
  1071.         norm = &(sp->norm)[4*i];
  1072.         
  1073.         n3f(norm);
  1074.         v3f(v);
  1075.     }
  1076.  
  1077.     endpolygon();
  1078.  
  1079. #ifdef HEDGEHOG
  1080.     for (i = 0; i < n; i++) {
  1081.         v = (sp->vert[i])->pos;
  1082.         norm = &(sp->norm)[4*i];
  1083.         draw_norm(v, norm);
  1084.     }
  1085. #endif /* HEDGEHOG */
  1086.     }
  1087.  
  1088. #ifdef HAS_BLENDING
  1089.     if (alpha_blended) {
  1090.     blendfunction(BF_ONE, BF_ZERO);
  1091.     zwritemask(0xffffff);
  1092.     }
  1093. #endif /* HAS_BLENDING */
  1094.  
  1095. }
  1096.  
  1097.  
  1098. draw_flat_surfs_1(Surf *start, Surf *finish)
  1099. {
  1100.     float *v, *nv, *e1, *e2, *tmp, buf[2][3], *norm;
  1101.     Surf *sp;
  1102.     int i, n;
  1103.  
  1104.     e1 = &buf[0][0];
  1105.     e2 = &buf[1][0];
  1106.     
  1107.     for (sp = start; sp < finish; sp++) {
  1108.  
  1109.     n = sp->n;
  1110.  
  1111.     v = (sp->vert[0])->pos;
  1112.     vec_op(e1, v, -, (sp->vert[n-1])->pos);
  1113.     
  1114.     for (i = 1; i < n; i++) {
  1115.         nv = (sp->vert[i])->pos;
  1116.         norm = &sp->norm[4*i];
  1117.         
  1118.         vec_op(e2, nv, -, v);
  1119.         cross(norm, e1, e2);
  1120.         normalize(norm);
  1121.  
  1122.         tmp = e1; e1 = e2; e2 = tmp;
  1123.         v = nv;
  1124.     }
  1125.  
  1126.     nv = (sp->vert[0])->pos;
  1127.     norm = &sp->norm[0];
  1128.     vec_op(e2, nv, -, v);
  1129.     cross(norm, e1, e2);
  1130.     normalize(norm);
  1131.     }
  1132. }
  1133.  
  1134.  
  1135. void
  1136. draw_smooth_surfs()
  1137. {
  1138.     Surf *sp;
  1139.     Atom **p;
  1140.     int n;
  1141.  
  1142.     /*
  1143.      * PHASE I: clear all normals
  1144.      */
  1145.     SLAVE_FUNC(DRAW_SMOOTH_SURFS_1);
  1146.     draw_smooth_surfs_1(model_atoms, end_model_atoms MASTER);
  1147.     WAIT_FOR_SLAVE();
  1148.  
  1149.     /*
  1150.      * PHASE II: accumulate for each atom all the normals to the surfaces
  1151.      *           it participates in
  1152.      */
  1153.     SLAVE_FUNC(DRAW_SMOOTH_SURFS_2);
  1154.     draw_smooth_surfs_2(model_surfs, end_model_surfs MASTER MASTER_PARAM);
  1155.     WAIT_FOR_SLAVE();
  1156.  
  1157.     /*
  1158.      * PHASE III: normalize the cumulative normals
  1159.      */
  1160.     SLAVE_FUNC(DRAW_SMOOTH_SURFS_3);
  1161.     draw_smooth_surfs_3(model_atoms, end_model_atoms MASTER);
  1162.     WAIT_FOR_SLAVE();
  1163.  
  1164.     /*
  1165.      * PHASE IV: draw the surfaces
  1166.      */
  1167.  
  1168. #ifdef HAS_BLENDING
  1169.     if (alpha_blended) {
  1170.     blendfunction(BF_SA, BF_MSA);
  1171.     zwritemask(0);
  1172.     }
  1173. #endif /* HAS_BLENDING */
  1174.  
  1175.     lmbind(MATERIAL, MODEL_MATERIAL_INDEX);
  1176.  
  1177.     for (sp = model_surfs; sp < end_model_surfs TOTAL; sp++) {
  1178.  
  1179.     n = sp->n;
  1180.  
  1181.     bgnpolygon();
  1182.  
  1183.     for (p = &sp->vert[0]; p < &sp->vert[n]; p++) {
  1184.         n3f((*p)->norm MASTER);
  1185.         v3f((*p)->pos);
  1186.     }
  1187.  
  1188.     endpolygon();
  1189.  
  1190. #ifdef HEDGEHOG
  1191.     for (p = &sp->vert[0]; p < &sp->vert[n]; p++)
  1192.         draw_norm((*p)->pos, (*p)->norm MASTER);
  1193. #endif /* HEDGEHOG */
  1194.     }
  1195.  
  1196. #ifdef HAS_BLENDING
  1197.     if (alpha_blended) {
  1198.     blendfunction(BF_ONE, BF_ZERO);
  1199.     zwritemask(0xffffff);
  1200.     }
  1201. #endif /* HAS_BLENDING */
  1202.  
  1203. }
  1204.  
  1205.  
  1206. draw_smooth_surfs_1(Atom *start, Atom *finish)
  1207. {
  1208.     Atom *ap;
  1209.  
  1210.     for (ap = start; ap < finish; ap++) {
  1211.  
  1212. #ifdef MP
  1213.  
  1214.     {
  1215.         int i;
  1216.  
  1217.         for (i = 1; i < nproc; i++)
  1218.         ap->norm [i] [X] =
  1219.         ap->norm [i] [Y] =
  1220.         ap->norm [i] [Z] = 0.;
  1221.     }
  1222.  
  1223. #endif /* MP */
  1224.  
  1225.     ap->norm MASTER [X] =
  1226.     ap->norm MASTER [Y] =
  1227.     ap->norm MASTER [Z] = 0.;
  1228.     }
  1229. }
  1230.  
  1231.  
  1232. draw_smooth_surfs_2(Surf *start, Surf *finish, CPU_PARAM_TYPE)
  1233. {
  1234.     float *v, *nv, *e1, *e2, *tmp, buf[2][3], norm[3];
  1235.     Surf *sp;
  1236.     Atom **p;
  1237.     int n;
  1238.  
  1239.     e1 = &buf[0][0];
  1240.     e2 = &buf[1][0];
  1241.     
  1242.     for (sp = start; sp < finish; sp++) {
  1243.  
  1244.     n = sp->n;
  1245.  
  1246.     v = (sp->vert[0])->pos;
  1247.     vec_op(e1, v, -, (sp->vert[n-1])->pos);
  1248.     
  1249.     for (p = &sp->vert[1]; p < &sp->vert[n]; p++) {
  1250.         nv = (*p)->pos;
  1251.         vec_op(e2, nv, -, v);
  1252.         cross(norm, e1, e2);
  1253.         normalize(norm);
  1254.  
  1255.         vec_op(p[-1]->norm CPU, p[-1]->norm CPU, +, norm);
  1256.  
  1257.         tmp = e1; e1 = e2; e2 = tmp;
  1258.         v = nv;
  1259.     }
  1260.  
  1261.     nv = (sp->vert[0])->pos;
  1262.     vec_op(e2, nv, -, v);
  1263.     cross(norm, e1, e2);
  1264.     normalize(norm);
  1265.  
  1266.     vec_op(p[-1]->norm CPU, p[-1]->norm CPU, +, norm);
  1267.     }
  1268. }
  1269.  
  1270.  
  1271. draw_smooth_surfs_3(Atom *start, Atom *finish)
  1272. {
  1273.     Atom *ap;
  1274.  
  1275.     for (ap = start; ap < finish; ap++) {
  1276.  
  1277. #ifdef MP
  1278.  
  1279.         {
  1280.         int i;
  1281.  
  1282.         for (i = 1; i < nproc; i++)
  1283.                 vec_op(ap->norm MASTER,
  1284.                ap->norm MASTER, +, ap->norm[i]);
  1285.         }
  1286.  
  1287. #endif /* MP */
  1288.  
  1289.         normalize(ap->norm MASTER);
  1290.     }
  1291. }
  1292.  
  1293.  
  1294. void
  1295. draw_springs()
  1296. {
  1297.     Spring *spring;
  1298.  
  1299.     if (mode == COLOR_MAP)
  1300.     color(YELLOW);
  1301.     else
  1302.     RGBcolor(200, 200, 20);
  1303.  
  1304.     for (spring = model_springs; spring < end_model_springs TOTAL; spring++) {
  1305.     bgnline();
  1306.       v3f(spring->from->pos);
  1307.       v3f(spring->to->pos);
  1308.     endline();
  1309.     }
  1310. }
  1311.